package com.alks.function.service.serviceImpl.finance.fincons;


import com.alibaba.excel.EasyExcel;
import com.alibaba.excel.ExcelWriter;
import com.alks.common.aop.AutoPageAop;
import com.alks.common.aop.RedisLock;
import com.alks.common.data.thread.UserIdThread;
import com.alks.common.utils.BigDecimalUtil;
import com.alks.common.utils.DateUtils;
import com.alks.common.utils.beanutils.ObjectUtils;
import com.alks.common.utils.excelUtils.ExcelUtils;
import com.alks.entity.data.entity.SdCompany;
import com.alks.entity.data.enums.MonthEnum;
import com.alks.entity.data.response.ResponseInfo;
import com.alks.entity.exception.ServiceErrorException;
import com.alks.function.data.dto.finance.fincons.*;
import com.alks.function.data.request.finance.fincons.AnnualPayableRequest;
import com.alks.function.data.request.finance.fincons.SettlementPayableRequest;
import com.alks.function.handler.excel.ReportReconciliationStatisticsStyleHandler;
import com.alks.function.mapper.SdCompanyMapper;
import com.alks.function.mapper.finance.fincons.AnnualPayableMapper;
import com.alks.function.mapper.finance.fincons.SettlementPayableMapper;
import com.alks.function.service.finance.fincons.AnnualPayableService;
import com.github.pagehelper.PageInfo;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang3.StringUtils;
import org.apache.poi.ss.usermodel.Sheet;
import org.apache.poi.ss.usermodel.Workbook;
import org.apache.poi.ss.usermodel.WorkbookFactory;
import org.springframework.beans.BeanUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import javax.servlet.http.HttpServletResponse;
import java.io.FileOutputStream;
import java.io.IOException;
import java.math.BigDecimal;
import java.net.URLEncoder;
import java.util.*;
import java.util.concurrent.atomic.AtomicReference;
import java.util.stream.Collectors;
import java.util.stream.Stream;

@Service
@Slf4j
public class AnnualPayableServiceImpl implements AnnualPayableService {

    @Autowired
    private AnnualPayableMapper annualPayableMapper;

    @Autowired
    private SettlementPayableMapper settlementPayableMapper;

    @Autowired
    private SdCompanyMapper sdCompanyMapper;

    /**
     * 查询付款明细/月份、总金额
     * @param request
     * @return
     */
    @Override
    @AutoPageAop
    public ResponseInfo getPaymentDetailsAndMonthAndAmount(AnnualPayableRequest request) {
        String companyId = UserIdThread.get().getCompanyId();

        //判断厂商是否为空
        List<PaymentDetailsDto> list = null;
        //统计数量
        BigDecimal count = BigDecimal.ZERO.setScale(2, BigDecimal.ROUND_HALF_UP); // 初始化为0并设置保留两位小数
        if(StringUtils.isBlank(request.getVendorName())){
            //厂商为空的情况
            list = annualPayableMapper.getPaymentDetailsAndMonthAndAmount(companyId,request);
            if(ObjectUtils.isNotEmpty(list)){
                List<PaymentDetailsDto> list1 = list.stream()
                        .filter(dto -> !dto.getVendorNo().equals("WKCL"))
                        .collect(Collectors.toList());
                PaymentDetailsDto d = list1.get(0);
                for (PaymentDetailsDto dto : list) {
                    //count += Optional.ofNullable(dto.getAmt()).orElse(0.0);
                    count = count.add(Optional.ofNullable(dto.getAmt())
                            .map(BigDecimal::new)
                            .orElse(BigDecimal.ZERO)
                            .setScale(2, BigDecimal.ROUND_HALF_UP));
                    //显示尾款处理
                        if(dto.getVendorNo().equals("WKCL")){
                            dto.setRemark(dto.getVendorName());
                            dto.setVendorName(d.getVendorName());
                            dto.setVendorNo(d.getVendorNo());
                        }
                }
            }
        }else{
            //厂商不为空的情况
            list = annualPayableMapper.getPaymentDetailsAndMonthAndAmountByVendor(companyId,request);
            if(ObjectUtils.isNotEmpty(list)){
                for (PaymentDetailsDto dto : list) {
                    //count += Optional.ofNullable(dto.getAmt()).orElse(0.0);
                    count = count.add(Optional.ofNullable(dto.getAmt())
                            .map(BigDecimal::new)
                            .orElse(BigDecimal.ZERO)
                            .setScale(2, BigDecimal.ROUND_HALF_UP));
                }
            }
        }

        HashMap map = new HashMap<>();
        PageInfo page = new PageInfo(list);
        map.put("total",page.getTotal());
        map.put("list",list);
        map.put("count",count);
        return ResponseInfo.ok(map);
    }

    /**
     * 导出付款明细/月份
     * @param request
     * @param response
     */
    @Override
    public void exportPaymentDetails(AnnualPayableRequest request, HttpServletResponse response)   throws IOException {
        //查询全部数据
        String companyId = UserIdThread.get().getCompanyId();

        //判断厂商是否为空
        List<PaymentDetailsDto> list = null;
        //统计数量
        Double count = 0.0;
        if(StringUtils.isBlank(request.getVendorName())){
            //厂商为空的情况
            list = annualPayableMapper.getPaymentDetailsAndMonthAndAmount(companyId,request);
            if(ObjectUtils.isNotEmpty(list)){
                List<PaymentDetailsDto> list1 = list.stream()
                        .filter(dto -> !dto.getVendorNo().equals("WKCL"))
                        .collect(Collectors.toList());
                PaymentDetailsDto d = list1.get(0);
                for (PaymentDetailsDto dto : list) {
                    count += Optional.ofNullable(dto.getAmt()).orElse(0.0);
                    //显示尾款处理
                    if(dto.getVendorNo().equals("WKCL")){
                        dto.setRemark(dto.getVendorName());
                        dto.setVendorName(d.getVendorName());
                        dto.setVendorNo(d.getVendorNo());
                    }
                }
            }
        }else{
            //厂商不为空的情况
            list = annualPayableMapper.getPaymentDetailsAndMonthAndAmountByVendor(companyId,request);
            if(ObjectUtils.isNotEmpty(list)){
                for (PaymentDetailsDto dto : list) {
                    count += Optional.ofNullable(dto.getAmt()).orElse(0.0);
                }
            }
        }

        Map<String, Object> map = new HashMap<>();
        map.put("count",count);
        ExcelUtils.creatByTemplate(response,"付款明细模板.xls","付款明细_"+ DateUtils.dateTimeNow(),list,map);
    }

    /**
     * 导出（结算应付汇总/年度查询）
     * @param request
     * @param response
     */
    @Override
    public void exportSettlementSummary(AnnualPayableRequest request, HttpServletResponse response) throws IOException {
        //查询所有数据
        String companyId = UserIdThread.get().getCompanyId();
        List<SettlementSummaryDto> list = settlementPayableMapper.getSettlementPayableSummaryByAnnual(companyId,request);

        //统计数量
        BigDecimal amt = BigDecimal.ZERO;//总金额
        BigDecimal balanceAmt = BigDecimal.ZERO;//已对账金额
        BigDecimal unBalanceAmt = BigDecimal.ZERO;//未对账金额
        BigDecimal apAmt = BigDecimal.ZERO;//已付金额
        BigDecimal unApAmt = BigDecimal.ZERO;//未付金额
        if(ObjectUtils.isNotEmpty(list)){
            for (SettlementSummaryDto dto : list) {
                BigDecimal currentAmt = dto.getAmt() != null ? dto.getAmt() : BigDecimal.ZERO;
                BigDecimal currentBalanceAmt = dto.getBalanceAmt() != null ? dto.getBalanceAmt() : BigDecimal.ZERO;
                BigDecimal currentUnBalanceAmt = dto.getUnBalanceAmt() != null ? dto.getUnBalanceAmt() : BigDecimal.ZERO;
                BigDecimal currentApAmt = dto.getApAmt() != null ? dto.getApAmt() : BigDecimal.ZERO;
                BigDecimal currentUnApAmt = dto.getUnApAmt() != null ? dto.getUnApAmt() : BigDecimal.ZERO;
//                BigDecimal currentUnAmtDq = dto.getUnAmtDq() != null ? dto.getUnAmtDq() : BigDecimal.ZERO;
//                BigDecimal currentUnAmtYq = dto.getUnAmtYq() != null ? dto.getUnAmtYq() : BigDecimal.ZERO;

                amt = amt.add(currentAmt);
                balanceAmt = balanceAmt.add(currentBalanceAmt);
                unBalanceAmt = unBalanceAmt.add(currentUnBalanceAmt);
                apAmt = apAmt.add(currentApAmt);
                unApAmt = unApAmt.add(currentUnApAmt);
            }
        }

        Map<String, Object> map = new HashMap<>();
        map.put("amt",amt);
        map.put("balanceAmt",balanceAmt);
        map.put("unBalanceAmt",unBalanceAmt);
        map.put("apAmt",apAmt);
        map.put("unApAmt",unApAmt);
        ExcelUtils.creatByTemplate(response,"结算应付汇总模板.xls","结算应付汇总_"+ DateUtils.dateTimeNow(),list,map);
    }

    /**
     * 导出对账统计表
     * @param financeYear   统计年份
     * @param response
     */
    @Override
    public void exportReconciliationStatistics(String financeYear, HttpServletResponse response)  throws IOException {
        //公司名字
        String companyId = UserIdThread.get().getCompanyId();
        SdCompany companyDto = sdCompanyMapper.findAllBYCompanyId(companyId);
        String companyName = companyDto.getAbbrName();
        String fileNamePrefix = financeYear + "年" + companyName;

        /*厂商12个月份对账详细统计*/
        // 构建详细请求
        SettlementPayableRequest detailRequest = new SettlementPayableRequest();
        detailRequest.setYy(financeYear);
        // 查询当月明细
        List<SettlementSummaryDto> monthList = settlementPayableMapper.getSettlementSummaryByMonth(companyId, detailRequest);
        if(ObjectUtils.isEmpty(monthList)){
            throw new ServiceErrorException("没有数据");
        }

        /*厂商该年的未对账*/

        List<List<Object>> data1 = new ArrayList<>();
        List<List<Object>> data2 = new ArrayList<>();

        String fileName1 = fileNamePrefix + "对账统计表";
        String fileName2 = fileNamePrefix + "对账统计明细表";
        int sheet1 = 0;
        int sheet2 = 1;

        // 获取月份数据并排序
        List<String> months = Arrays.stream(MonthEnum.values())
                .map(MonthEnum::getMonth)
                .collect(Collectors.toList())
                .stream()
                .sorted().collect(Collectors.toList());

        generateHead(sheet1, data1, fileName1);
        generateHead(sheet2, data2, fileName2);

        Map<String, Object> monthCount = new HashMap<>();
        Map<String, MonthItemDTO> monthDetailCount = new HashMap<>();

        // 统计所有厂商得总未对账和期末结欠
        AtomicReference<BigDecimal> balanceAmtTotal = new AtomicReference<>(BigDecimal.ZERO); //总计：所有厂商的已对账之和
        AtomicReference<BigDecimal> unBalanceAmtTotal = new AtomicReference<>(BigDecimal.ZERO); //总计：所有厂商的未对账之和
        AtomicReference<BigDecimal> unApAmtTotal = new AtomicReference<>(BigDecimal.ZERO); //总计：所有厂商的未付之和 （期末结欠）

        // 按厂商分组
        //Map<String, List<SettlementSummaryDto>> vendorMap = monthList.stream()
        //        .filter(e -> StringUtils.isNotEmpty(e.getVendorName()))
        //        .collect(Collectors.groupingBy(SettlementSummaryDto::getVendorName));
        // 按 VendorName 分组，并确保 vendorMap 按 VendorName 升序排序
        Map<String, List<SettlementSummaryDto>> vendorMap = monthList.stream()
                .filter(e -> StringUtils.isNotEmpty(e.getVendorName()))
                .filter(e -> StringUtils.isNotEmpty(e.getVendorNo()))
                .collect(Collectors.groupingBy(
                        SettlementSummaryDto::getVendorName,
                        TreeMap::new, // 使用 TreeMap 来保持键值（即 VendorName）的自然顺序
                        Collectors.toList() // 将每个分组的结果收集为列表
                ));

        vendorMap.forEach((key, value) -> {
            List<Object> item1 = new ArrayList<>();
            item1.add(key);
            item1.add(null); // 账期

            List<Object> item2 = new ArrayList<>();
            item2.add(key);

            Map<String, SettlementSummaryDto> monthMap = null;
            try {
                //获取月份不为空得数据
                monthMap = value.stream()
                        .filter(e -> StringUtils.isNotEmpty(e.getFinanceYymm()))
                        .collect(Collectors.toMap(e -> e.getFinanceYymm().substring(4), e -> e));
            } catch (IllegalStateException ex) {
                ex.printStackTrace();
                throw new ServiceErrorException("数据异常，存在重复数据");
            }
            Map<String, SettlementSummaryDto> finalMonthMap = monthMap;
            AtomicReference<BigDecimal> balanceAmtCount = new AtomicReference<>(BigDecimal.ZERO); //当前厂商当年的已对账之和
            AtomicReference<BigDecimal> unBalanceAmtCount = new AtomicReference<>(BigDecimal.ZERO); //当前厂商当年的未对账之和
            AtomicReference<BigDecimal> unApAmtCount = new AtomicReference<>(BigDecimal.ZERO); //当前厂商当年的未付之和（期末结欠）
            months.forEach((month) -> {
                BigDecimal balance = null;
                MonthItemDTO monthItemDTO = null;
                if (finalMonthMap.containsKey(month)) {
                    //if (finalMonthMap.get(month).getBalanceAmt().compareTo(BigDecimal.ZERO) > 0) {

                        //获取当前厂商的当年总期末结欠和未对账数据
                        BigDecimal balanceAmt = finalMonthMap.get(month).getBalanceAmt(); //当月的
                        balanceAmtCount.set(BigDecimalUtil.add(balanceAmtCount.get(), balanceAmt));//计算当前厂商当年的总对账数据
                        BigDecimal unBalanceAmt = finalMonthMap.get(month).getUnBalanceAmt(); //当月的
                        unBalanceAmtCount.set(BigDecimalUtil.add(unBalanceAmtCount.get(), unBalanceAmt));//计算当前厂商当年的总未对账数据
                        BigDecimal unApAmt = finalMonthMap.get(month).getUnApAmt(); //当月的
                        unApAmtCount.set(BigDecimalUtil.add(unApAmtCount.get(), unApAmt));//计算当前厂商当年的总未付数据（期末结欠）

                        balance = finalMonthMap.get(month).getBalanceAmt();
                        monthItemDTO = new MonthItemDTO(finalMonthMap.get(month).getBalanceAmt(),
                                finalMonthMap.get(month).getApAmt(), finalMonthMap.get(month).getUnApAmt());

                        if (monthCount.containsKey(month)) {
                            monthCount.put(month, BigDecimalUtil.add((BigDecimal) monthCount.get(month), balance));
                        } else {
                            monthCount.put(month, balance);
                        }
                        if (monthDetailCount.containsKey(month)) {
                            monthDetailCount.get(month).add(monthItemDTO);
                        } else {
                            monthDetailCount.put(month, monthItemDTO);
                        }
                   // }
                } else {
                    if (!monthCount.containsKey(month)) {
                        monthCount.put(month, null);
                    }
                    if (!monthDetailCount.containsKey(month)) {
                        monthDetailCount.put(month, new MonthItemDTO());
                    }
                }
                item1.add(balance);
                item2.add(monthItemDTO == null ? null : monthItemDTO.getBalanceAmt()); //已对账
                item2.add(monthItemDTO == null ? null : monthItemDTO.getApAmt());  //已支付
                item2.add(monthItemDTO == null ? null : monthItemDTO.getUnApAmt()); //未支付
            });

            // 总计：获取所有厂商得 期末结欠（已对账之和）总计以及未对账总计
            balanceAmtTotal.set(BigDecimalUtil.add(balanceAmtTotal.get(), balanceAmtCount.get())); //总计：所有厂商的已对账之和
            // 获取当前厂商月份为空未对账数据合计
            BigDecimal unCount = value.stream()
                    .filter(e -> StringUtils.isEmpty(e.getFinanceYymm()))
                    .map(SettlementSummaryDto::getUnBalanceAmt)
                    .reduce(BigDecimal.ZERO, BigDecimal::add);
            unBalanceAmtCount.set(BigDecimalUtil.add(unBalanceAmtCount.get(), unCount));
            unBalanceAmtTotal.set(BigDecimalUtil.add(unBalanceAmtTotal.get(), unBalanceAmtCount.get())); //总计：所有厂商的未对账之和
            unApAmtTotal.set(BigDecimalUtil.add(unApAmtTotal.get(), unApAmtCount.get())); //总计：所有厂商的未付之和（期末结欠）

            item1.add(unApAmtCount.get().compareTo(BigDecimal.ZERO) == 0 ? null : unApAmtCount.get()); // 期末结欠
            item1.add(null); // 到期应付款
            item1.add(null); // 备注
            data1.add(item1);



            item2.add(unBalanceAmtCount.get().compareTo(BigDecimal.ZERO) == 0 ? null : unBalanceAmtCount.get()); // 未对账
            item2.add(unApAmtCount.get().compareTo(BigDecimal.ZERO) == 0 ? null : unApAmtCount.get()); // 期末结欠
            item2.add(null); // 到期未付
            item2.add(null); // 备注
            data2.add(item2);
        });

        // 生成统计数据
        generateCount(sheet1, data1, monthCount, months, unApAmtTotal.get(),unBalanceAmtTotal.get());
        generateCount(sheet2, data2, monthDetailCount, months, unApAmtTotal.get(),unBalanceAmtTotal.get());

        ExcelWriter excelWriter = null;
        try {
            response.setContentType("application/vnd.openxmlformats-officedocument.spreadsheetml.sheet");
            response.setCharacterEncoding("utf-8");
            //response.setHeader("Content-Disposition", "attachment;filename=" + fileNamePrefix + "对账表_" +System.currentTimeMillis() + ".xlsx");
            // 解决文件名乱码问题
            String encodedFileName = URLEncoder.encode(  "对账表_" + fileNamePrefix + "-"+ System.currentTimeMillis() + ".xlsx", "UTF-8").replaceAll("\\+", "%20");
            response.setHeader("Content-Disposition", "attachment; filename=" + encodedFileName);

            excelWriter = EasyExcel.write(response.getOutputStream())
                    .registerWriteHandler(new ReportReconciliationStatisticsStyleHandler(data1.size(), data2.size()))
                    .build();

            excelWriter.write(data1, EasyExcel.writerSheet(sheet1, fileName1).build());
            excelWriter.write(data2, EasyExcel.writerSheet(sheet2, fileName2).build());
        } catch (Exception ex) {
            ex.printStackTrace();
        } finally {
            //关闭流
            assert excelWriter != null;
            excelWriter.finish();
        }
    }

    /**
     * 更新对账数据
     */
    @Override
    @RedisLock(key = "task:FinanceFinconsTask.ScheduleInsertPcCostTtlTask")
    @Transactional
    public ResponseInfo updateStatistics() {
        try{
            // 结算应付月份汇总：PC_V_COST_TTL>>>PcCostTtlTask(先全删除再写入数据)

            //1.结算应付汇总月的全查询
            List<SettlementSummaryDto> list = settlementPayableMapper.getPcVCostTtl();
            if(ObjectUtils.isEmpty(list)){
                throw new ServiceErrorException("没有数据");
            }

            //第一次清洗数据，先删除
            settlementPayableMapper.deletePcCostTtlTask();

            List<SettlementSummaryDto2> addList = new ArrayList<>();
            for (SettlementSummaryDto dto : list) {
                SettlementSummaryDto2 dateDato = new SettlementSummaryDto2();
                BeanUtils.copyProperties(dto, dateDato);
                addList.add(dateDato);
            }

            if(ObjectUtils.isNotEmpty(list)){
                settlementPayableMapper.batchInsertPcCostTtlTask(addList);
            }

            log.info(" 结算应付月份汇总’PC_COST_TTL_TASK数据更新addList:{}", addList.size() ,"成功！");

            return ResponseInfo.ok();
        }catch (Exception e){
            e.printStackTrace();
            throw new ServiceErrorException(e.getMessage());
        }
    }

    /**
     * 生成表头
     * @param sheetNo   工作表序号
     * @param data      所有行数据
     * @param fileName  文件名称
     */
    private void generateHead(int sheetNo, List<List<Object>> data, String fileName) {
        List<Object> head = new ArrayList<>();
        if (sheetNo == 0) {
            head.add("厂商");
            head.add("账期");
            head.addAll(Arrays.stream(MonthEnum.values())
                    .map(e -> e.getIndex() + "月对账")
                    .collect(Collectors.toList()));
            head.add("期末结欠");
            head.add("到期应付款");
            head.add("备注");

            data.add(Collections.nCopies(head.size(), fileName));
            data.add(head);
        } else {
            head.add("厂商");
            head.addAll(Arrays.stream(MonthEnum.values())
                    .flatMap(e -> Collections.nCopies(3, e.getIndex() + "月份").stream())
                    .collect(Collectors.toList()));
            head.add("未对账");
            head.add("期末结欠");
            head.add("到期未付");
            head.add("备注");

            List<Object> head2 = new ArrayList<>();
            head2.add("厂商");
            head2.addAll(Arrays.stream(MonthEnum.values())
                    .flatMap(e -> Stream.of("已对账", "已支付", "未支付"))
                    .collect(Collectors.toList()));
            head2.add("未对账");
            head2.add("期末结欠");
            head2.add("到期未付");
            head2.add("备注");

            data.add(Collections.nCopies(head.size(), fileName));
            data.add(head);
            data.add(head2);
        }
    }

    /**
     * 生成统计数据
     * @param sheetNo   工作表序号
     * @param data      所有行数据
     * @param countMap  统计数据Map
     * @param months    月份数据
     */
    private void generateCount(int sheetNo, List<List<Object>> data, Map countMap, List<String> months, BigDecimal unApAmtTotal,BigDecimal unBalanceAmtTotal) {
        List<Object> dataCount = new ArrayList<>();
        if (sheetNo == 0) {
            dataCount.add(null);
            dataCount.add(null);
            months.forEach((month) -> {
                dataCount.add(((Map<String, Object>) countMap).get(month));
            });
            dataCount.add(unApAmtTotal.compareTo(BigDecimal.ZERO) == 0 ? null : unApAmtTotal); // 期末结欠
            dataCount.add(null); // 到期应付款
            dataCount.add(null); // 备注
            data.add(dataCount);
        } else {

            List<Object> dataCount2 = new ArrayList<>();
            dataCount2.add(null);
            months.forEach((month) -> {
                dataCount2.add(((MonthItemDTO) countMap.get(month)).getBalanceAmt());
                dataCount2.add(((MonthItemDTO) countMap.get(month)).getApAmt());
                dataCount2.add(((MonthItemDTO) countMap.get(month)).getUnApAmt());
            });
            dataCount2.add(unBalanceAmtTotal.compareTo(BigDecimal.ZERO) == 0 ? null : unBalanceAmtTotal); // 未对账
            dataCount2.add(unApAmtTotal.compareTo(BigDecimal.ZERO) == 0 ? null : unApAmtTotal); // 期末结欠
            dataCount2.add(null); // 到期未付
            dataCount2.add(null); // 备注
            data.add(dataCount2);
        }
    }

    /*导出分页*/
    public void exportToExcel(List<SettlementStatisticsDto> list) throws IOException {
        Workbook workbook = WorkbookFactory.create(true); // 创建一个新的 Excel 工作簿

        // 创建第一页并填充数据
        Sheet sheet1 = workbook.createSheet("第一页");
        fillSheet(sheet1, list);

        // 创建第二页并填充数据
        Sheet sheet2 = workbook.createSheet("第二页");
        fillSheet(sheet2, list); // 这里填充的数据可以是不同的数据，根据你的需求填充

        // 将数据写入到文件
        try (FileOutputStream fileOut = new FileOutputStream("导出数据.xlsx")) {
            workbook.write(fileOut);
        }

        // 关闭工作簿
        workbook.close();
    }

    private void fillSheet(Sheet sheet, List<SettlementStatisticsDto> list) {
        // 在这里填充你的数据到指定的 sheet 中，逻辑与之前填充第一页的数据类似
    }



}